#ifndef _PFS_H
#define _PFS_H

#include <stddef.h>
#include <stdint.h>
#include <sys/select.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <signal.h>
#include <pthread.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <math.h>
#include <assert.h>
#include <ctype.h>
#include <semaphore.h>
#include "unicode/ustring.h"

void inicializarFUSE();

#define HANDSHAKE 0x00
#define FAIL 0x01
#define PPD 0x02
#define PRAID 0x03
#define GETSECTOR 	0x10
#define RTASECTOROK	0x11
#define WRITESECTOR	0x12

#define SECTOR_SIZE 512
#define BLOCK_SIZE 1024
#define CLUSTER_SIZE 4096
#define ENTRY_SIZE 4
#define ULTIMO_CLUSTER 0x0FFFFFFF
#define CLUSTER_LIBRE 0x00000000
#define ESCRITURA 1
#define LECTURA 0
#define STDIN 0


/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
									MACROS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
#ifndef _MAXDESC_
		#define _MAXDESC_
		#define MAXDESC( maximo, nuevo ) maximo = ( (maximo > nuevo ) ? maximo : nuevo );
#endif

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
								ESTRUCTURAS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
typedef uint8_t ST_SECTOR[SECTOR_SIZE];
typedef uint8_t ST_CLUSTER[CLUSTER_SIZE];
typedef uint8_t ST_BLOQUE[BLOCK_SIZE];

typedef struct ST_PFS{
	char	szIp[16];
	int		iPuerto;
	char	szIpRemoto[16];
	int		iPuertoRemoto;
	int		iMaxConexiones;
	int		iTamCache;
	int		iSectoresxBloque;
	int		iSocketRemoto;
} __attribute__ ((packed)) ST_PFS;

typedef struct ST_ARGS{
	int 	argc;
	char 	*argv[];
} __attribute__ ((packed)) ST_ARGS;

typedef struct ST_NIPC{
    unsigned char     		ucType;
    int32_t            		lPayload;
    int						sector;
    ST_SECTOR				buffer;
} __attribute__ ((packed)) ST_NIPC;

typedef struct {
	uint8_t  jmpBoot[3];
	uint8_t  OEMName[8];
	uint16_t bytesPorSector;
	uint8_t  sectorPorCluster;
	uint16_t reservedSectorCount;
	uint8_t  numberFATs;
	uint16_t rootEntCnt;			/*(numero de entradas de directorios para FAT12/16)Para FAT32 este campo debe ser 0*/
	uint16_t totalSector16;			/*(sectores de todas las regiones para FAT12/16) Para FAT32 este campo debe ser 0*/
	uint8_t  media;  				/*indica medio extraible o fijo*/
	uint16_t sectorPorFAT16;		/*numeros de sectores ocupados para FAT12/16 - para FAT32 este campo debe ser 0*/
	uint16_t sectorPorTrack;
	uint16_t numberHeads;
	uint32_t countHiddenSectors;  	/*sectores ocultos*/
	uint32_t totalSectors32;		/*sectores totales en el volumen, para FAT32*/

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 los campos que siguen son solo definidos para volumenes de FAT32, no para FAT12 ni 16
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

	uint32_t sectorPorFAT32;        /* numero de sectores ocupados por una fat */
	uint16_t FATFlags;				/* Bits 0-3: Zero-based number of active Fat. Valid if mirroring is disabled
										Bits 4-6: Reserved
										Bit 7: 0 = FAT mirrored into all FATs at runtime. 1 = only 1 FAT active
										Bits 8-15: Reserved */
	uint16_t version;
	uint32_t rootCluster;			/* numero de cluster del primer cluster del directorio raíz, por lo general 2*/
	uint16_t rootFSInfo;			/* numero de sector de la estructura de informacion en el area reservada, por lo general 1*/
	uint16_t backupBootSector;		/* indica el sector del area reservada donde se encuentra una copia del boot sector
										si es 0 entonces no hay copia*/
	uint8_t reserved[12];			/*reservado para futuras expansiones*/
	uint8_t driverNumber;
	uint8_t reserved1;
	uint8_t extBootSignature;
	uint32_t volumeID;
	uint8_t volumeLabel[11];
	uint8_t FSType[8];
} __attribute__ ((packed)) ST_BOOTSECTOR;

typedef struct ST_FSINFOSECTOR{
	uint32_t	sectorSignature;
	uint8_t		reserved[480];
	uint32_t	countClusterFree;	/*numero de clusters libres, -1 si se desconoce la cantidad*/
	uint32_t	allocatedCluster;	/*numero del ultimo cluster mas recientemente asignado*/
	uint8_t		reserved1[12];
	uint32_t	sectorSignature1;
} __attribute__ ((packed)) ST_FSINFOSECTOR;

typedef struct ST_DIRECTORY{
	uint8_t		name[8];
	uint8_t		extension[3];
	uint8_t		attributes;
	uint8_t		reserved;
	uint8_t		crtTimeTenth;
	uint16_t	crtTime;
	uint16_t	crtDate;
	uint16_t	lstAccDate;
	uint16_t	fstClusHi;
	uint16_t	wrtTime;
	uint16_t	wrtDate;
	uint16_t	fstClusLo;
	uint32_t	fileSize;		/*el tamanio esta en bytes*/
} __attribute__ ((packed)) ST_DIRECTORY;

typedef struct ST_LONG_NAME{
	uint8_t sequenceN;
	uint16_t nameStart[5];
	uint8_t attributes;			/*siempre 0x0F*/
	uint8_t reserved;			/*siempre 0x00*/
	uint8_t checksum;
	uint16_t nameMiddle[6];
	uint16_t firstCluster;		/*siempre 0x0000*/
	uint16_t nameEnd[2];
} __attribute__ ((packed)) ST_LONG_NAME;

typedef struct ST_FILE_ENTRY{
	int tieneLongName;			/*1 si tiene long name, 0 si no lo tiene*/
	ST_LONG_NAME longNameEntry;
	ST_DIRECTORY dataEntry;
} __attribute__ ((packed)) ST_FILE_ENTRY;

typedef struct ST_LISTA_FILE_ENTRY {
	ST_FILE_ENTRY fileEntry;
	struct ST_LISTA_FILE_ENTRY * next;
} __attribute__ ((packed)) ST_LISTA_FILE_ENTRY;


//typedef struct ST_LISTA_CACHE {
//	uint32_t				uContador;
//	ST_FILE_ENTRY			uArchivo;
//	uint8_t 				*uContenidoArch;
//	struct ST_LISTA_CACHE	*next;
//}__attribute__ ((packed)) ST_LISTA_CACHE;
//
//typedef struct ST_NODO_CACHE {
//	ST_FILE_ENTRY			uArchivo;
//	uint8_t 				*uContenidoArch;
//}__attribute__ ((packed)) ST_NODO_CACHE;

typedef struct ST_CACHE {  //segun el tamanio de cache, habra 1,2,4 u 8 de estas estructuras.
	ST_CLUSTER		bufferCache;
	uint32_t 		numeroCluster;  // ver si es necesario
}__attribute__ ((packed)) ST_CACHE;

typedef struct ST_LISTA_CACHE {
	uint32_t				uContador;	//necesario para saber cuantos utilizan esta cache (hablado con el ayudante)
	char 					path[300];  //path del archivo cacheado
	sem_t 					semaforoDeUso;
	uint32_t 				primerClusterCache;
	ST_CACHE				*cache;
	struct ST_LISTA_CACHE	*next;
}__attribute__ ((packed)) ST_LISTA_CACHE;


/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
							VARIABLES GLOBALES
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
ST_BOOTSECTOR 	bootSector;
ST_PFS			stPFS;
ST_ARGS			stARGS;
ST_DIRECTORY    rootDirectory;
//fd_set			maestroLecturaFD, descLecturaFD, maestroEscrituraFD, descEscrituraFD;
//int				iMaxDescriptor;
sem_t			semaforoConexiones;
sem_t			semaforoListaCache;
sem_t			semaforoTablaFAT;
ST_LISTA_CACHE	*stCache;
uint32_t		bytesOcupados;
uint32_t		*fatTable;

#endif
